#ifndef QQTLONGDATAPROTOCOL_H
#define QQTLONGDATAPROTOCOL_H

#include <QObject>

#include <qqtlongdataserialization.h>
#include <qqtprotocol.h>

#include <qqtframe.h>

#include <qqthighgrade_global.h>

/**
 * @brief The QQtLongDataProtocol class
 * 用于发送和接收很长的数据。
 *
 * 原理：
 * 序列化数据会被拆分成多个序列化数据分多次发送，收到多个序列化数据后顺序组装为一个反序列化数据发给上层。
 *
 * 使用json序列化、反序列化数据。
 * 数据base64传输，可以避免分包的开头、结尾上的中文乱码。
 *
 * 约束：
 * 不能直接使用二进制数据，
 * QQtLongDataSerialization使用json作为序列化数据，字典在序列化成json的时候，二进制数据会丢失，
 * 用户可以手动base64运算一下自己的二进制数据，再加数据压缩或许也是不错的选择。
 *
 * 必然和QQtLongDataSerialization配合使用。
 */
class QQTHIGHGRADESHARED_EXPORT QQtLongDataProtocol : public QQtProtocol
{
    Q_OBJECT

public:
    explicit QQtLongDataProtocol ( QObject* parent = 0 );
    virtual ~QQtLongDataProtocol();

    //1024, 2048, 4096, 8192, 16384, ...
    void setSendBufferSize ( int len = 1024 );
    int getSendBufferSize();

    //9, 14, ...
    void setUUidWordLength ( int len = 9 );
    int getUUidWordLength();

    //true, false
    void setAppendLastWord ( bool open = true );
    bool getAppendLastWord();

    //把最后<100字节追加到倒数第二个报文上。mBufferSize, +100
    void setAppendLastWordSize ( int size = 100 );
    bool getAppendLastWordSize();

    //网络中传输的json数据做Base64转换，为了让jsondata支持二进制，这是默认的。
    enum TranslateDataEncoding
    {
        RAW_DATA, //中文在buffer开头结尾的时候会乱码，原因未知
        HEX_DATA, //转换后体积较大。而且如果HEX和内部协议、校验码发生重叠，都是问题。
        BASE64_DATA, //转换后体积较大。

        DATAENCODE_MAX
    };
    void setTranslateDataEncoding ( TranslateDataEncoding type = BASE64_DATA );
    TranslateDataEncoding getTranslateDataEncoding();

    enum CompressMethod
    {
        NoCompress = 0,
        ZlibCompress,
        GZipCompress,

        CompressMethodMax,
    };

    void setCompressTranslateData ( CompressMethod method = NoCompress );
    CompressMethod getCompressTranslateData();

    //内部的Recv检测时钟，必须开着。
    void setTimerInterval ( int millsecond = 6000 );
    int timerInterval();

    void setCleanTimerInterval ( int millsecond = 30000 );
    int cleanTimerInterval();

    void setAutoCleanDataCache ( bool open = true );

    //默认每隔一段时间调用一下。
    virtual void clearDataCache();

    //已经序列化好buffer
    virtual void sendMessage ( const QQtLongDataSerialization& data );

    //已经反序列化好buffer
    virtual void recvMessage ( const QQtLongDataSerialization& data );

signals:
    void readyRead ( const QQtLongDataSerialization& data );

    /**
     * 以下与用户无关。
     */

signals:
    void updateSendBytes ( int send, int total );
    void updateSendProgress ( int progress );

signals:
    void updateRecvBytes ( int send, int total );
    void updateRecvProgress ( int progress );

protected:
    virtual void protectedSendMessage ( const QQtLongDataSerialization& data );
    virtual void protectedRecvMessage ( const QQtLongDataSerialization& data );

protected slots:
    void slotTimeout();
    void slotCleanTimeout();
private:
    QQtDictionary mDataCache;

    int mBufferSize;
    int mUUidLen;
    int mAppendLastWordSize;
    bool mAppendLastWord;
    TranslateDataEncoding mTranslateDataEncode;
    CompressMethod mCompressMethod;

    QMutex mLock;
    bool mRecvFlag;
    QTimer* m_timer;
    QTimer* m_CleanTimer;

    // QQtProtocol interface
public:
    virtual quint16 minlength() override {
        QQtLongDataSerialization ds0;
        return ds0.minlength();
    }
    virtual quint16 maxlength() override {
        QQtLongDataSerialization ds0;
        return ds0.maxlength();
    }
    virtual quint16 splitter ( const QByteArray& _l ) override {
        QByteArray bytes = _l.left ( minlength() );
        quint32 header, size;
        bytes >> header >> size;
        return size;
    }
    virtual bool dispatcher ( const QByteArray& _l ) override;
    virtual void initializer() override {}
};

#endif // QQTLONGDATAPROTOCOL_H

